package xyz.erupt.jpa.task;

import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author 黄锦贤
 * @version 1.0
 * @email 996842803@qq.com
 * @date 2022/8/26
 */
@SuppressWarnings("DuplicatedCode")
@Slf4j
public class AsyncFutures {
    /**
     * 异步处理任务
     *
     * @param tasks        任务
     * @param corePoolSize 核心线程数
     * @throws InterruptedException
     */
    public static void runNoRes(List<Runnable> tasks, int corePoolSize) throws InterruptedException {
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        // 任务长度
        int len = tasks.size();
        // 手动创建线程池
        ExecutorService executors = new ThreadPoolExecutor(corePoolSize, len + corePoolSize + 1,
                0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        // 创建计时器
        CountDownLatch countDownLatch = new CountDownLatch(len);
        try {
            // 执行任务内容
            for (int i = 0; i < tasks.size(); i++) {
                int finalI = i;
                CompletableFuture.runAsync(() -> {
                    try {
                        tasks.get(finalI).run();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        //计时--
                        countDownLatch.countDown();
                    }
                }, executors);
            }
            //等待计时为0
            countDownLatch.await();
            // 停止计时
            stopwatch.stop();
            // 获取调用类信息
            StackTraceElement ste = Thread.currentThread().getStackTrace()[2];
            // 打印相关信息
            log.info("并发执行耗时:{}s,任务数:{},并发量:{},调用类:{} ({}) [Line:{}]",
                    stopwatch.elapsed(TimeUnit.SECONDS),
                    tasks.size(),
                    corePoolSize,
                    ste.getClassName(),
                    ste.getMethodName(),
                    ste.getLineNumber());
        } catch (Exception e) {
            log.error("AsyncFutures,执行错误:" + e.getMessage());
            // 抛出错误
            throw e;
        } finally {
            // 关闭线程池
            executors.shutdown();
        }
    }

    /**
     * 异步处理任务
     *
     * @param tasks        任务
     * @param corePoolSize 核心线程数
     * @return
     * @throws InterruptedException
     */
    public static FutureResult run(List<Callable<?>> tasks, int corePoolSize) throws InterruptedException {
        // 创建计时器
        Stopwatch stopwatch = Stopwatch.createStarted();
        // 任务长度
        int len = tasks.size();
        // 手动创建线程池
        ExecutorService executors = new ThreadPoolExecutor(corePoolSize, len + corePoolSize + 1,
                0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        // 创建计时器
        CountDownLatch countDownLatch = new CountDownLatch(len);
        // 创建调度任务
        List<Object> futures = new ArrayList<>(len);
        try {
            // 执行任务内容
            for (int i = 0; i < tasks.size(); i++) {
                futures.add(null);
                int finalI = i;
                CompletableFuture.runAsync(() -> {
                    try {
                        futures.set(finalI, tasks.get(finalI).call());
                    } catch (Exception e) {
                        e.printStackTrace();
                        futures.set(finalI, e);
                    } finally {
                        //计时--
                        countDownLatch.countDown();
                    }
                }, executors);
            }
            //等待计时为0
            countDownLatch.await();
            // 停止计时
            stopwatch.stop();
            // 获取调用类信息
            StackTraceElement ste = Thread.currentThread().getStackTrace()[2];
            // 打印相关信息
            log.info("并发执行耗时:{}s,任务数:{},并发量:{},调用类:{} ({}) [Line:{}]",
                    stopwatch.elapsed(TimeUnit.SECONDS),
                    tasks.size(),
                    corePoolSize,
                    ste.getClassName(),
                    ste.getMethodName(),
                    ste.getLineNumber());
            // 返回结果
            return new FutureResult(futures);
        } catch (Exception e) {
            log.error("AsyncFutures,执行错误:" + e.getMessage());
            // 抛出错误
            throw e;
        } finally {
            // 关闭线程池
            executors.shutdown();
        }
    }
}
